﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Practices.Unity;
using SkeletonNET.Crud;
using Microsoft.Practices.ServiceLocation;
using System.Data.Entity;
using Moq;
using System.Data.Objects.DataClasses;
using SkeletonNET.Crud.Repository;
using SkeletonNET.Base.Crud.UnitOfWork;
using SkeletonNET.Crud.KeyCache;

namespace SkeletonNET.Data.Tests
{
    [TestClass]
    public partial class RepositoryTests
    {
        [TestInitialize]
        public void Initialize()
        {
            // Setup the container and register it with the ServiceLocator
            var container = new UnityContainer();
            ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(container));
            container.RegisterInstance<IUnityContainer>(container);

            // Register an implementation of IRepository
            container.RegisterType(typeof(IRepository<>), typeof(Repository<>));
            // Register an implementation of IUnitOfWork
            container.RegisterType<IUnitOfWork, FakeDbContext>();
            // Register the keycache
            container.RegisterType<IEntityKeyCache, EntityKeyCache>();
        }

        [TestMethod]
        public void TestRepositoryInject()
        {
            // Inject the repository
            var repository = ServiceLocator.Current.GetInstance<IRepository<TestEntity>>();

            // Insert a new instance of TestEntity into the repo
            repository.Insert(new TestEntity() { ID = 100 });

            // Check if the entity was added
            var item = repository.GetQuery().Where(x => x.ID == 100).ToList();

            // Save all the data
            repository.Save();

            Assert.IsNotNull(repository);
            Assert.IsTrue(item.Count() > 0);
        }

        [TestMethod]
        public void TestDeleteByIDAndGetByID()
        {
            // Inject the repository
            var repository = ServiceLocator.Current.GetInstance<IRepository<TestEntity>>();
            // Inject a new UoW to make sure that we start from 0
            repository.UnitOfWork = ServiceLocator.Current.GetInstance<IUnitOfWork>();

            // Add some data
            for (int i = 0; i < 10; i++)
                repository.Insert(new TestEntity() { ID = i });

            // Verify that the entity with id 5 exists
            Assert.IsTrue(repository.GetByID(5) != null);

            // Delete the record with id 5
            repository.DeleteByID(5);

            // Verify that the entity with id 5 was deleted
            var search = repository.GetByID(5);
            Assert.IsTrue(search == null);
        }

        [TestMethod]
        public void TestUpdate()
        {
            // Inject repository
            var repository = ServiceLocator.Current.GetInstance<IRepository<TestEntity>>();
            // Inject a clean UoW
            repository.UnitOfWork = ServiceLocator.Current.GetInstance<IUnitOfWork>();

            // Add data
            for (int i = 0; i < 10; i++)
                repository.Insert(new TestEntity() { ID = i });

            // Get the entity with id 2
            var data = repository.GetQuery()
                .Where(x => x.ID == 2)
                .Single();

            // Update the data
            data.ID = 10000;
            
            // Get the data again to do the checks on it
            var data2 = repository.GetQuery()
                .Where(x => x.ID == 10000)
                .Single();

            Assert.IsTrue(data2.ID == 10000);
        }

        [TestMethod]
        public void TestSharedUOW()
        {
            // Inject a UnitOfWork implementation
            var uow = ServiceLocator.Current.GetInstance<IUnitOfWork>();

            var repo1 = ServiceLocator.Current.GetInstance<IRepository<TestEntity>>();
            var repo2 = ServiceLocator.Current.GetInstance<IRepository<TestEntity2>>();

            // Override the default unitofwork instance
            repo1.UnitOfWork = uow;
            repo2.UnitOfWork = uow;

            repo1.Insert(new TestEntity() { ID = 200 });
            repo2.Insert(new TestEntity2() { ID = 500 });

            // Save the data of repo1 & repo2 into the UoW
            // This has the same effect as calling repo1.Save() because of the UoW being shared.
            uow.Commit();

            // Check if the unit of work has the new entity
            Assert.IsTrue(uow.GetQuery<TestEntity>().Where(x => x.ID == 200).Count() > 0);
            Assert.IsTrue(uow.GetQuery<TestEntity2>().Where(x => x.ID == 500).Count() > 0);
        }
    }
}